package net.easyjava.third.db.nosql.redis;

import net.easyjava.tools.lang.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;

import java.io.IOException;
import java.util.*;

/**
 * Created by wenxiaoning on 16/6/27.
 */
public class RedisClient {
    private static Logger logger = LoggerFactory.getLogger(RedisClient.class);
    private static String ip;
    private static int port;
    private static String password;
    private static JedisPool pool;
    /**
     * 构造单例
     */
    private volatile static RedisClient singleton;
    private RedisClient(final String ip,final int port,final String password){
        this.ip = ip;
        this.port = port;
        this.password = password;
        init();

    }
    public static RedisClient getInstance(final String ip,final int port,final String password) {
        if (singleton == null) {
            synchronized (RedisClient.class) {
                if (singleton == null) {
                    System.out.println("RedisClient.getInstance");
                    singleton = new RedisClient(ip,port, password);
                }
            }
        }
        if(pool == null){
            init();
        }
        return singleton;
    }
    private static synchronized void init(){
        if (pool == null) {
            System.out.println("RedisClient.init");
            // 建立连接池配置参数
            JedisPoolConfig config = new JedisPoolConfig();

            // 设置最大连接数
            config.setMaxActive(300);

            // 设置最大阻塞时间，记住是毫秒数milliseconds
            config.setMaxWait(1000);

            // 设置空间连接
            config.setMaxIdle(100);
            pool = new JedisPool(config, ip, port,1000,password);
            logger.debug("init redis pool ip:{} port:{}", ip, port);
        }
    }

    /**
     * 获取一个连接
     * @return
     */
    public  Jedis getJedis(){
        if(pool == null){
            init();
        }
        return pool.getResource();
    }
    /**
     * 归还一个连接
     *
     * @param jedis
     */
    public  void returnResource(Jedis jedis) {
        pool.returnResource(jedis);
    }

    /**
     * 销毁连接池
     */
    public void destroy(){
        pool.destroy();
    }


    /**
     * 批量添加
     * @param keyValues
     * @throws IOException
     */
    public void setBatch(Map keyValues) throws IOException {
        Jedis jedis = getJedis();
        Pipeline p = jedis.pipelined();
        Set<Map.Entry<String,Object>> set = keyValues.entrySet();

        Iterator<Map.Entry<String,Object>> iter = set.iterator();
        while(iter.hasNext()){
            Map.Entry<String,Object> entry = iter.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            byte[] valueBytes = SerializeUtil.serialize(value);
            p.set(key.getBytes(),valueBytes);

        }
        p.sync();
        if (jedis != null) {
            returnResource(jedis);
        }
    }


    /**
     * 保存数据
     * @param key
     * @param value
     */
    public void set(String key, Object value) throws IOException {
        byte[] bytes = SerializeUtil.serialize(value);
        Jedis jedis = getJedis();
        jedis.set(key.getBytes(), bytes);
        if (jedis != null) {
            returnResource(jedis);
        }
    }


    /**
     * 获取数据
     * @param key
     * @return
     */
    public Object get(String key) {
        Object result = null;
        Jedis jedis = null;
        try {
            if (!StringTools.isEmpty(key)) {
                jedis = getJedis();
                byte[] value = jedis.get(key.getBytes());
                result = SerializeUtil.unserialize(value);
//                System.out.println("result = " + result.toString());
                //logger.debug("get  key[" + key + "] ,value:" + result);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return result;
    }


    /**
     * get incr value
     * @param key
     * @return
     */
    public  Long getIncr(String key){
        Long result = 0l;
        Jedis jedis = null;
        try {
            if (!StringTools.isEmpty(key)) {
                jedis = getJedis();
                String value = jedis.get(key);
                if(value == null){
                    result = 0l;
                }else{
                    result = Long.valueOf(value);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return result;
    }

    //get keySet

    public  Set<String> getKeys(String key) {
        Set<String> objectSet = new HashSet<String>();
        Jedis jedis = null;
        try {
            if (!StringTools.isEmpty(key)) {
                jedis = getJedis();
                Set<byte[]> set = jedis.keys(key.getBytes());
                for (byte[] value : set) {
                    String k = new String(value);
                    logger.debug("key:" + k);
                    //objectSet.add(String.valueOf(SerializeUtil.unserialize(value)));
                    objectSet.add(k);
                }
                logger.debug("get  key[" + key + "] ,value:" + objectSet.size());
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return objectSet;
    }

    /**
     * 根据传入的格式获取key
     * @param key
     * @return 数组
     * @author LBQ-PC
     * @date:2015年1月30日
     */
    public  String[] getArrayKeys(String key) {
        String[] arrayKeys = null;
        Jedis jedis = null;
        try {
            if (!StringTools.isEmpty(key)) {
                jedis = getJedis();
                Set<byte[]> set = jedis.keys(key.getBytes());
                arrayKeys = new String[set.size()];
                int i=0;
                for (byte[] value : set) {
                    String k = new String(value);
                    logger.debug("key:" + k);
                    arrayKeys[i]=k;
                    i++;
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return arrayKeys;
    }

    /**
     * 根据传入的数组批量删除key
     * @param  keys
     * @author LBQ-PC
     * @date:2015年1月30日
     */
    public  void removeByKeys(String[] keys) {
        try {
            Jedis jedis = null;
            try {
                jedis = getJedis();
                if(keys!=null && keys.length>0) {
                    jedis.del(keys);
                    logger.debug("del key[" + keys + "]");
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                if (jedis != null) {
                    returnResource(jedis);
                }
            }
        } catch (Exception e) {
            logger.error("remove element error! key[" + keys + "]", e);
        }
    }

    public  void remove(String key) {
        try {
            Jedis jedis = null;
            try {
                jedis = getJedis();
                jedis.del(key.getBytes());
                logger.debug("del key[" + key + "]");
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                if (jedis != null) {
                    returnResource(jedis);
                }
            }
        } catch (Exception e) {
            logger.error("remove element error! key[" + key + "]", e);
        }
    }

    /**
     * ====================String======end============
     */


    /**
     * ====================List=====start=============
     */


    public  void setList(String key, List value) {
        try {
            if (!StringTools.isEmpty(key) && value != null) {
                byte[] bytes = SerializeUtil.serializeList(value);
                if (bytes != null) {
                    Jedis jedis = null;
                    try {
                        jedis = getJedis();
                        jedis.set(key.getBytes(), bytes);
                        logger.debug("set key[" + key + "],value[" + value + "]");
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    } finally {
                        if (jedis != null) {
                            returnResource(jedis);
                        }
                    }
                }
            } else {
                logger.warn("set key[" + key + "],value[" + value + "] is invalid");
            }
        } catch (Exception e) {
            logger.error("set key[" + key + "],value[" + value + "] is error", e);
        }
    }

    /**
     * =======================getList
     *
     * @param key
     * @return
     */
    public  List getList(String key) {
        List result = null;
        Jedis jedis = null;
        try {
            if (!StringTools.isEmpty(key)) {
                jedis = getJedis();
                byte[] value = jedis.get(key.getBytes());
                result = SerializeUtil.unserializeList(value);
                // logger.debug("get  key[" + key + "] ,value:" + result);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return result == null ? new ArrayList() : result;
    }


    /**
     * List中删除某个元素【全部删除】
     *
     * @param key
     * @param value
     */
    public  void ldel(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.lrem(key, 0, value);//0 删除全部
            logger.debug("lrem key[" + key + "],value[" + value + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }


    /**
     * rpush a value to List bottom
     * @param key
     * @param value
     */
    public  void rpush(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.rpush(key, value);
            logger.debug("rpush key[" + key + "],value[" + value + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }
    /**
     * rpushBatch str[] to List bottom
     * @param key
     * @param params
     */
    public  void rpushBatch(String key,String... params) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.rpush(key, params);
            logger.debug("rpush key[" + key + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }

    /**
     * lpush a value to List top
     * @param key
     * @param value
     */
    public  void lpush(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.lpush(key, value);
            logger.debug("rpush key[" + key + "],value[" + value + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }
    /**
     * lpushBatch str[] value to List top
     * @param key
     * @param params
     */
    public  void lpushBatch(String key,String... params) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.lpush(key, params);
            logger.debug("rpush key[" + key + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }
    /**
     * lrange
     * @param key
     */
    public  List<String> lrange(String key,Long start ,Long end) {

        List<String> result = new ArrayList<String>();
        if(start>end){
            logger.warn("start can't > end , so return null array");
            return result;
        }
        Jedis jedis = null;
        try {
            jedis = getJedis();
            result = jedis.lrange(key, start, end);
            logger.debug("rpush key[" + key + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e.fillInStackTrace());
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return result;
    }

    public  boolean exists(String key) {
        Jedis jedis = null;
        boolean flag = false;
        try {
            jedis = getJedis();
            flag = jedis.exists(key.getBytes());
            logger.debug("exsist key[" + key + "]");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
            return flag;
        }
    }

    /**
     * 自增，每次+1
     * @param key
     * @return
     */
    public  Long incr(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            Long num = jedis.incr(key);
            logger.debug("incr key[" + key + "]");
            return num;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return -1L;
    }
    /**
     * 按指定长度增加
     * @param key
     * @param integer
     * @return
     */

    public  Long incrBy(String key,int integer) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            Long num = jedis.incrBy(key, integer);
            logger.debug("incrBy key[" + key + "]");
            return num;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
        return -1L;
    }

    /**
     * ====================reset=====Cache=============
     */
    public  void resetDB() {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.flushDB();
            logger.debug("resetDB =========");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
        }
    }

    //get redis DB size
    public  long getDBSize() {
        Jedis jedis = null;
        long size = 0;
        try {
            jedis = getJedis();
            size = jedis.dbSize();
            logger.debug("getDBSize =========");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (jedis != null) {
                returnResource(jedis);
            }
            return size;
        }
    }



    public static void main(String[] args) {
//        RedisClient client = RedisClient.getInstance("114.215.147.115",6080,"Zz2015zZ");
        // 建立连接池配置参数
        JedisPoolConfig config = new JedisPoolConfig();

        // 设置最大连接数
        config.setMaxActive(300);

        // 设置最大阻塞时间，记住是毫秒数milliseconds
        config.setMaxWait(1000);

        // 设置空间连接
        config.setMaxIdle(100);
        JedisPool pool = new JedisPool(config, "101.201.53.141", 6381,1000,"Newo2016");
        Jedis jedis = pool.getResource();
        jedis.set("test","test");


        long isSuccess = jedis.expire("test", 10);
        System.out.println("isSuccess = " + isSuccess);
        long time = jedis.persist("test");
        System.out.println("time = " + time);





        pool.returnResource(jedis);
    }

}
